Universal App Configuration
Configure your universal app's appearance, behavior, and security settings through config/config.json.
App Name
Set the display name that appears in device launchers, app stores, and system settings.
Configuration
{"WEBVIEW_CONFIG": {"android": {"appName": "My Awesome App"},"ios": {"appName": "My Awesome App"}}}
Platform-Specific Names
{"WEBVIEW_CONFIG": {"android": {"appName": "MyApp for Android"},"ios": {"appName": "MyApp for iOS"}}}
App Icon
Customize app icons for both Android and iOS platforms.
Android Icons
Place density-specific icons in public/android/appIcons/:
| Density | Filename | Size (px) |
|---|---|---|
mdpi | icon-mdpi.png | 48 x 48 |
hdpi | icon-hdpi.png | 72 x 72 |
xhdpi | icon-xhdpi.png | 96 x 96 |
xxhdpi | icon-xxhdpi.png | 144 x 144 |
xxxhdpi | icon-xxxhdpi.png | 192 x 192 |
Supported formats: PNG, JPG, JPEG
Behavior:
- Automatically applied during build
- Missing densities use nearest available resource
- Falls back to default Catalyst icon if none provided
iOS Icons
Place icons in public/ios/appIcons/ following the pattern: icon-{size}-{scale}.{ext}
| Filename | Size (px) | Purpose |
|---|---|---|
| icon-20x20-2x.png | 40×40 | iPhone Notification |
| icon-20x20-3x.png | 60×60 | iPhone Notification |
| icon-29x29-2x.png | 58×58 | iPhone Settings |
| icon-29x29-3x.png | 87×87 | iPhone Settings |
| icon-40x40-2x.png | 80×80 | iPhone Spotlight |
| icon-40x40-3x.png | 120×120 | iPhone Spotlight |
| icon-60x60-2x.png | 120×120 | iPhone App |
| icon-60x60-3x.png | 180×180 | iPhone App |
| icon-1024x1024-1x.png | 1024×1024 | App Store |
Supported formats: PNG, JPG, JPEG
File Structure
your-project/├── public/│ ├── android/appIcons/│ │ ├── icon-mdpi.png│ │ ├── icon-hdpi.png│ │ ├── icon-xhdpi.png│ │ ├── icon-xxhdpi.png│ │ └── icon-xxxhdpi.png│ └── ios/appIcons/│ ├── icon-20x20-2x.png│ ├── icon-20x20-3x.png│ ├── icon-29x29-2x.png│ ├── icon-29x29-3x.png│ ├── icon-40x40-2x.png│ ├── icon-40x40-3x.png│ ├── icon-60x60-2x.png│ ├── icon-60x60-3x.png│ └── icon-1024x1024-1x.png
Splashscreen
Configure a custom splashscreen displayed during app startup.
Configuration
{"WEBVIEW_CONFIG": {"splashScreen": {"duration": 2000,"backgroundColor": "#ffffff","imageWidth": 120,"imageHeight": 120,"cornerRadius": 20}}}
Options
| Property | Type | Default | Description |
|---|---|---|---|
duration | number | 1000 | Display time in milliseconds. Ignored when an HTML splash is used |
minDuration | number | 0 | Minimum time in milliseconds the HTML splash stays on screen |
backgroundColor | string | "#ffffff" | Background color (hex) |
imageWidth | number | 120 | Image width in dp/px |
imageHeight | number | 120 | Image height in dp/px |
cornerRadius | number | 20 | Corner radius (0 for square) |
Custom Images
Android: Place image at public/android/splashscreen.{png|jpg|webp}
- Supported: PNG, JPG, WebP
- Fallback: App launcher icon
iOS: Place image at public/ios/splashscreen.{png|jpg|jpeg}
- Recommended: PNG, 512x512px
- File size: Under 1MB
- Fallback: Progress bar with loader
HTML Splash
To show an animation while the app loads, add public/splashscreen.html. It goes at the root of public/, not in public/android or public/ios, and both platforms use the same file. It only takes effect when splashScreen is set in the config.
On launch the app shows the native splash image, then the HTML splash, and then the app once its first page has loaded. Set minDuration to keep the animation on screen for at least that many milliseconds, even when the page loads sooner. If the page takes longer than 10 seconds, the HTML splash is dismissed anyway. duration is ignored in this mode.
{"WEBVIEW_CONFIG": {"splashScreen": {"backgroundColor": "#ffffff","minDuration": 1200}}}
The file has a few rules:
- Keep it to one self-contained file. Put CSS and JavaScript inline and embed images as
data:URIs. - Paint your own opaque, full-screen background. The native image sits underneath.
- Do not make network requests. Android blocks them.
- The page has no access to the native bridge.
- Prefer CSS
transformandopacityanimations. The splash runs while the app is loading, so heavy JavaScript competes with it.
<!doctype html><html><head><meta name="viewport" content="width=device-width, initial-scale=1" /><style>html, body { margin: 0; height: 100%; background: #ffffff; }body { display: flex; align-items: center; justify-content: center; }.dot {width: 48px; height: 48px; border-radius: 50%; background: #3b5bdb;animation: pulse 1s ease-in-out infinite alternate;}@keyframes pulse {from { transform: scale(0.6); opacity: 0.4; }to { transform: scale(1); opacity: 1; }}</style></head><body><div class="dot"></div></body></html>
Delete the file to go back to the image-only splash.
Examples
Basic Splashscreen
{"WEBVIEW_CONFIG": {"splashScreen": {"duration": 2000,"backgroundColor": "#ffffff"}}}
Circular Icon
{"WEBVIEW_CONFIG": {"splashScreen": {"duration": 2000,"backgroundColor": "#1a1a1a","imageWidth": 150,"imageHeight": 150,"cornerRadius": 75}}}
Auto-Dismiss (iOS Only)
{"WEBVIEW_CONFIG": {"splashScreen": {"backgroundColor": "#ffffff"}}}
Omitting duration on iOS auto-dismisses when WebView loads.
Platform Differences
iOS:
- Auto-dismiss when
durationis omitted - Smooth fade-out animation
Android:
- Theme support (adapts to light/dark mode)
Best Practices
| App Load Time | Recommendation |
|---|---|
| < 1 second | Auto-dismiss (iOS) or 1000ms |
| 1-3 seconds | 2000-3000ms |
| > 3 seconds | Auto-dismiss (iOS) or 3000ms |
Performance Profiler
Enable the Catalyst Profiler for a debug build:
{"WEBVIEW_CONFIG": {"profiler": {"enabled": true}}}
Use Performance Profiling for the Android Chrome DevTools workflow, iOS trace export, captured signals, and the window.CatalystPerf API.
The profiler is disabled by default and only runs in debug builds. Rebuild the native app after changing the setting.
Edge-to-Edge
Let the WebView draw behind the status bar and navigation bar.
{"WEBVIEW_CONFIG": {"edgeToEdge": {"enabled": true,"statusBarStyle": "auto"}}}
Options
| Property | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Draw page content behind the system bars on Android and iOS |
statusBarStyle | string | "auto" | System bar icon colour. Android only for now |
statusBarStyle accepts these values:
autofollows the system light or dark theme.dark-contentuses dark icons, for light pages.light-contentuses light icons, for dark pages.
When edge-to-edge is enabled, the app is responsible for keeping content clear of the system bars. Read the insets with useSafeArea() and apply them as padding. The values are in CSS pixels on both platforms. On Android they also update when the insets change, for example when the user switches navigation mode. When edge-to-edge is disabled, the insets are 0.
On Android 10 (API 29) and later the system bars are fully transparent. Below API 29 the navigation bar keeps a translucent scrim.
Whitelisting
Control network access and navigation through URL whitelisting.
Configuration
{"WEBVIEW_CONFIG": {"accessControl": {"enabled": true,"allowedUrls": ["https://api.example.com/*","*.example.com","https://cdn.example.com/assets/*"]}}}
Options
| Property | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable URL whitelisting |
allowedUrls | string[] | [] | Permitted URL patterns |
Behavior:
enabled: true- Only whitelisted URLs accessible (default deny)enabled: false- All URLs accessible (no restrictions)
URL Patterns
Exact Match
{"allowedUrls": ["https://api.example.com/users","https://cdn.example.com/logo.png"]}
Wildcard Match
{"allowedUrls": ["https://api.example.com/*","https://*.example.com/api/*"]}
Subdomain Match
{"allowedUrls": ["*.example.com","*.cdn.example.com"]}
Examples
API Endpoints
{"accessControl": {"enabled": true,"allowedUrls": ["https://api.myapp.com/auth/*","https://api.myapp.com/users/*","https://api.myapp.com/data/*"]}}
CDN Resources
{"accessControl": {"enabled": true,"allowedUrls": ["https://cdn.jsdelivr.net/*","*.cloudfront.net"]}}
Third-Party Services
{"accessControl": {"enabled": true,"allowedUrls": ["https://maps.googleapis.com/*","https://api.stripe.com/*","*.analytics.google.com"]}}
How It Works
- All network requests blocked by default when enabled
- External links open in system browser
- URLs matched against patterns in order
- First matching pattern allows the request
- No match = request blocked
Security Benefits
- Default deny - Secure baseline blocks all unknown requests
- Explicit allow - Only whitelisted URLs accessible
- Navigation control - External links handled by system browser
Protocol Configuration
Control whether the webview uses HTTP or HTTPS protocol.
Configuration
{"WEBVIEW_CONFIG": {"useHttps": true}}
| Property | Type | Default | Description |
|---|---|---|---|
useHttps | boolean | false | Use HTTPS protocol |
Behavior:
true- Uses HTTPS protocolfalse- Uses HTTP protocol
Example: Development vs Production
{"WEBVIEW_CONFIG": {"useHttps": false, // HTTP for local development"accessControl": {"enabled": false}}}
{"WEBVIEW_CONFIG": {"useHttps": true, // HTTPS for production"accessControl": {"enabled": true,"allowedUrls": ["https://api.myapp.com/*"]}}}
Complete Configuration Example
{"WEBVIEW_CONFIG": {"port": "3005","LOCAL_IP": "192.168.XX.XX","appInfo": "android-v2.1.0","useHttps": true,"profiler": {"enabled": false},"android": {"appName": "My Awesome App","packageName": "com.example.myawesomeapp","buildType": "debug","sdkPath": "/Users/yourname/Library/Android/sdk","emulatorName": "Pixel_5_API_30","cachePattern": "*.css,*.js"},"ios": {"appName": "My Awesome App","appBundleId": "com.example.myawesomeapp","buildType": "Debug","simulatorName": "iPhone 17 Pro","cachePattern": "*.css,*.js"},"accessControl": {"enabled": true,"allowedUrls": ["https://api.myapp.com/*","https://cdn.myapp.com/*","*.cloudfront.net"]},"splashScreen": {"duration": 2000,"minDuration": 0,"backgroundColor": "#ffffff","imageWidth": 120,"imageHeight": 120,"cornerRadius": 20},"notifications": {"enabled": true}}}
Configuration Tips
- App Names - Keep under 30 characters for best display
- Icons - Provide all required sizes for professional appearance
- Splashscreen - Match duration to actual load time
- Whitelisting - Start with minimal URLs, add as needed
- Protocol - Always use HTTPS in production
- Testing - Test configuration on both platforms before release
- iOS Build Type - Use
DebugorReleasewith exact casing when you addWEBVIEW_CONFIG.ios.buildType
See Also
- Running Universal Apps - Build and run commands
- Hooks - Device capabilities
- Build Optimization - Performance tuning
- Cache Management - Cache configuration